package com.relytosoft.mizar.media.analyze.services.service.structure.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.relytosoft.dubhe.common.core.base.page.PageQuery;
import com.relytosoft.dubhe.common.core.exception.ServiceException;
import com.relytosoft.dubhe.common.core.utils.BeanCopyUtils;
import com.relytosoft.dubhe.common.satoken.entity.CurrentUser;
import com.relytosoft.mizar.media.analyze.api.entity.structure.AyStructureTaskSon;
import com.relytosoft.mizar.media.analyze.api.pojo.dto.AyStructureTaskSonDto;
import com.relytosoft.mizar.media.analyze.api.pojo.query.AyStructureTaskSonQuery;
import com.relytosoft.mizar.media.analyze.api.pojo.vo.AyBatchVo;
import com.relytosoft.mizar.media.analyze.api.pojo.vo.AyCameraVo;
import com.relytosoft.mizar.media.analyze.api.pojo.vo.AyStructureTaskSonVo;
import com.relytosoft.mizar.media.analyze.services.mapper.structure.AyStructureTaskSonMapper;
import com.relytosoft.mizar.media.analyze.services.service.structure.AyStructureTaskSonService;
import com.relytosoft.mizar.media.common.config.properties.MizarAnalyzeProperties;
import com.relytosoft.mizar.media.common.constant.MediaMqConstants;
import com.relytosoft.mizar.media.common.emqx.client.MqttOp;
import com.relytosoft.mizar.media.common.entity.pojo.dto.TaskRequestDto;
import com.relytosoft.mizar.media.common.enums.DeleteStatusEnum;
import com.relytosoft.mizar.media.common.enums.TaskStatusEnum;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * AyStructureTaskSonServiceImpl
 *
 * @Author SunLi
 * @Date: 2022/5/31 16:46
 * @Version 1.0
 */
@Service
public class AyStructureTaskSonServiceImpl extends ServiceImpl<AyStructureTaskSonMapper, AyStructureTaskSon> implements AyStructureTaskSonService {

    @Resource
    private MizarAnalyzeProperties analyzeProperties;

    @Override
    public IPage<AyStructureTaskSonVo> selectAyStructureTaskSonPageList(PageQuery pageQuery, AyStructureTaskSonQuery ayStructureTaskSonQuery) {
        if (StrUtil.isBlank(pageQuery.getOrderByColumn())) {
            pageQuery.setOrderByColumn("id");
            pageQuery.setIsAsc("desc");
        }
        if(StrUtil.isNotEmpty(ayStructureTaskSonQuery.getEndTime())){
            LocalDateTime endTime=  Convert.toLocalDateTime(ayStructureTaskSonQuery.getEndTime()).plusDays(1);
            ayStructureTaskSonQuery.setEndTime(endTime.format(DateTimeFormatter.ISO_LOCAL_DATE));
        }
        return baseMapper.selectPageTaskSonList(pageQuery.build(), ayStructureTaskSonQuery);
    }

    @Override
    public AyBatchVo insertAyStructureTaskSon(AyStructureTaskSonDto ayStructureTaskSonDto,String taskName) {
        //所有需要添加的设备id
        List<AyCameraVo> ayCameraVos = ayStructureTaskSonDto.getAyCameraVos();

        AyBatchVo ayBatchVo = new AyBatchVo();
        ayBatchVo.setTotal(ayCameraVos.size());
        //没有符合条件的设备
        if (!addFrontVerify(ayStructureTaskSonDto)) {
            ayBatchVo.setSuccess(0);
            ayBatchVo.setError(ayCameraVos.size());
            ayBatchVo.setErrorMsg(Collections.singletonList("没有符合创建条件的设备"));
            return ayBatchVo;
        }
        //构造子任务列表
        List<AyStructureTaskSon> ayStructureTaskSonList=new ArrayList<>();
        for (AyCameraVo cameraVo : ayStructureTaskSonDto.getAyCameraVos()) {
            AyStructureTaskSon ayStructureTaskSon = new AyStructureTaskSon();
            BeanCopyUtils.copy(cameraVo,ayStructureTaskSon);
            ayStructureTaskSon.setStructureTaskId(ayStructureTaskSonDto.getStructureTaskId());
            ayStructureTaskSon.setTaskName(taskName);
            ayStructureTaskSon.setStatus(TaskStatusEnum.CREATED.getValue());
            ayStructureTaskSon.setBeginTime(LocalDateTime.now());
            ayStructureTaskSonList.add(ayStructureTaskSon);
        }

        boolean insertResult=this.saveBatch(ayStructureTaskSonList);
        if(insertResult){
            ayBatchVo.setSuccess(ayStructureTaskSonList.size());
            ayBatchVo.setError(ayCameraVos.size() - ayStructureTaskSonList.size());
            ayBatchVo.setErrorMsg(Collections.singletonList("符合条件的任务已添加成功"));

            //发送EMQ消息
            ayStructureTaskSonList.forEach(a->this.sendInsertTaskMsg(a));

        }
        else{
            ayBatchVo.setSuccess(0);
            ayBatchVo.setError(ayCameraVos.size());
            ayBatchVo.setErrorMsg(Collections.singletonList("任务添加失败"));
        }
        return ayBatchVo;
    }

    @Override
    public boolean deleteAyStructureTaskSon(List<Integer> ids) {
        //运行中及创建中的任务不允许删除
        LambdaQueryWrapper<AyStructureTaskSon> wrapper =  Wrappers.lambdaQuery();
        wrapper.in(AyStructureTaskSon::getId, ids)
                .eq(AyStructureTaskSon::getIsDeleted, DeleteStatusEnum.NOT_DELETED.getValue())
                .ne(AyStructureTaskSon::getStatus,TaskStatusEnum.CREATED.getValue())
                .ne(AyStructureTaskSon::getStatus,TaskStatusEnum.RUNING.getValue());
        AyStructureTaskSon ayStructureTaskSon = new AyStructureTaskSon();
        ayStructureTaskSon.setIsDeleted(DeleteStatusEnum.DELETED.getValue());
        ayStructureTaskSon.setUpdatedId(CurrentUser.getCurrentUserId());
        ayStructureTaskSon.setUpdatedBy(CurrentUser.getCurrentUserFullName());
        boolean update =this.update(ayStructureTaskSon, wrapper);
        return update;
    }

    @Override
    public List<AyStructureTaskSon> selectCanStartTaskSonList(List<Integer> ids,Integer structureTaskId) {
        //未删除的已结束、未启动子任务
        LambdaQueryWrapper<AyStructureTaskSon> wrapper = Wrappers.lambdaQuery();
        if(!ids.isEmpty()){
            wrapper.in(AyStructureTaskSon::getId, ids);
        }
        if(structureTaskId!=null&&structureTaskId>0){
            wrapper.eq(AyStructureTaskSon::getStructureTaskId,structureTaskId);
        }
        wrapper.eq(AyStructureTaskSon::getIsDeleted,DeleteStatusEnum.NOT_DELETED.getValue());
        List<Integer> status=new ArrayList<>(Arrays.asList(TaskStatusEnum.FINISHED.getValue(),TaskStatusEnum.NOT_STARTED.getValue()));
        wrapper.in(AyStructureTaskSon::getStatus,status);
        return this.list(wrapper);
    }
    @Override
    public List<AyStructureTaskSon> selectCanStopTaskSonList(List<Integer> ids,Integer structureTaskId) {
        //未删除的运行中、异常、创建中（更新时间已过配置）的子任务
        LambdaQueryWrapper<AyStructureTaskSon> wrapper = Wrappers.lambdaQuery();
        if(!ids.isEmpty()){
            wrapper.in(AyStructureTaskSon::getId, ids);
        }
        if(structureTaskId!=null&&structureTaskId>0){
            wrapper.eq(AyStructureTaskSon::getStructureTaskId,structureTaskId);
        }
        wrapper.eq(AyStructureTaskSon::getIsDeleted,DeleteStatusEnum.NOT_DELETED.getValue());
        List<Integer> status=new ArrayList<>(Arrays.asList(TaskStatusEnum.RUNING.getValue(),TaskStatusEnum.UNUSUAL.getValue()));
        wrapper.and(w -> w.in(AyStructureTaskSon::getStatus,status).or(w1->w1.eq(AyStructureTaskSon::getStatus,TaskStatusEnum.CREATED.getValue()).lt(AyStructureTaskSon::getUpdatedTime,LocalDateTime.now().plusSeconds(-1*analyzeProperties.getTaskCanStopTime()))));
        return this.list(wrapper);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteAndStartTaskSonList(List<AyStructureTaskSon> deleteSonList,List<AyStructureTaskSon> insertSonList,Integer structureTaskId){
        boolean result=false;
        if(structureTaskId!=null&&structureTaskId>0){
            //已结束未删除的子任务需要删除再启动
            LambdaQueryWrapper<AyStructureTaskSon> wrapper =  Wrappers.lambdaQuery();
            wrapper.eq(AyStructureTaskSon::getStructureTaskId,structureTaskId);
            wrapper.eq(AyStructureTaskSon::getIsDeleted, DeleteStatusEnum.NOT_DELETED.getValue());
            wrapper.eq(AyStructureTaskSon::getStatus, TaskStatusEnum.FINISHED.getValue());
            AyStructureTaskSon ayStructureTaskSon = new AyStructureTaskSon();
            ayStructureTaskSon.setIsDeleted(DeleteStatusEnum.DELETED.getValue());
            ayStructureTaskSon.setUpdatedId(CurrentUser.getCurrentUserId());
            ayStructureTaskSon.setUpdatedBy(CurrentUser.getCurrentUserFullName());
            int rowCount=baseMapper.update(ayStructureTaskSon, wrapper);
            result =rowCount==deleteSonList.size();
        }
        else if(!deleteSonList.isEmpty()){
            result=this.updateBatchById(deleteSonList,deleteSonList.size());
        }
        if(result){
            result=this.saveBatch(insertSonList,insertSonList.size());
        }
        if(!result){
            throw new ServiceException("启动子任务失败");
        }
        return result;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean startTaskSonList(List<AyStructureTaskSon> startSonList,Integer structureTaskId){
        //未启动、未删除的子任务可启动
        LambdaQueryWrapper<AyStructureTaskSon> wrapper =  Wrappers.lambdaQuery();
        if(structureTaskId!=null&&structureTaskId>0){
            wrapper.eq(AyStructureTaskSon::getStructureTaskId,structureTaskId);
        }
        else if(!startSonList.isEmpty()){
            List<Integer> ids=startSonList.stream().map(AyStructureTaskSon::getId).collect(Collectors.toList());
            wrapper.in(AyStructureTaskSon::getId, ids);
        }
        wrapper.eq(AyStructureTaskSon::getIsDeleted, DeleteStatusEnum.NOT_DELETED.getValue());

        wrapper.eq(AyStructureTaskSon::getStatus,TaskStatusEnum.NOT_STARTED.getValue());
        AyStructureTaskSon ayStructureTaskSon = new AyStructureTaskSon();
        ayStructureTaskSon.setStatus(TaskStatusEnum.CREATED.getValue());
        ayStructureTaskSon.setUpdatedId(CurrentUser.getCurrentUserId());
        ayStructureTaskSon.setUpdatedBy(CurrentUser.getCurrentUserFullName());
        ayStructureTaskSon.setBeginTime(LocalDateTime.now());
        ayStructureTaskSon.setEndTime(null);
        int rowCount=baseMapper.update(ayStructureTaskSon, wrapper);
        return rowCount==startSonList.size();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean stopTaskSonList(List<AyStructureTaskSon> stopSonList,Integer structureTaskId) {
        if(structureTaskId!=null&&structureTaskId>0) {
            //运行中的子任务可停止
            LambdaQueryWrapper<AyStructureTaskSon> wrapper =  Wrappers.lambdaQuery();
            wrapper.eq(AyStructureTaskSon::getStructureTaskId,structureTaskId);
            wrapper.eq(AyStructureTaskSon::getIsDeleted, DeleteStatusEnum.NOT_DELETED.getValue());
            //wrapper.eq(AyStructureTaskSon::getStatus,TaskStatusEnum.RUNING.getValue());

            List<Integer> status=new ArrayList<>(Arrays.asList(TaskStatusEnum.RUNING.getValue(),TaskStatusEnum.UNUSUAL.getValue()));
            wrapper.and(w -> w.in(AyStructureTaskSon::getStatus,status).or(w1->w1.eq(AyStructureTaskSon::getStatus,TaskStatusEnum.CREATED.getValue()).lt(AyStructureTaskSon::getUpdatedTime,LocalDateTime.now().plusSeconds(-1*analyzeProperties.getTaskCanStopTime()))));
            AyStructureTaskSon ayStructureTaskSon = new AyStructureTaskSon();
            ayStructureTaskSon.setStatus(TaskStatusEnum.FINISHED.getValue());
            ayStructureTaskSon.setUpdatedId(CurrentUser.getCurrentUserId());
            ayStructureTaskSon.setUpdatedBy(CurrentUser.getCurrentUserFullName());
            ayStructureTaskSon.setEndTime(LocalDateTime.now());
            int rowCount=baseMapper.update(ayStructureTaskSon, wrapper);
            return rowCount==stopSonList.size();
        }
        else if(!stopSonList.isEmpty()){
            return this.updateBatchById(stopSonList,stopSonList.size());
        }
        return false;
    }

    @Override
    public boolean deleteByTask(List<Integer> ids) {
        //运行中及创建中的任务不允许删除
        LambdaQueryWrapper<AyStructureTaskSon> wrapper =  Wrappers.lambdaQuery();
        wrapper.in(AyStructureTaskSon::getStructureTaskId, ids)
                .eq(AyStructureTaskSon::getIsDeleted, DeleteStatusEnum.NOT_DELETED.getValue())
                .ne(AyStructureTaskSon::getStatus,TaskStatusEnum.CREATED.getValue())
                .ne(AyStructureTaskSon::getStatus,TaskStatusEnum.RUNING.getValue());
        AyStructureTaskSon ayStructureTaskSon = new AyStructureTaskSon();
        ayStructureTaskSon.setIsDeleted(DeleteStatusEnum.DELETED.getValue());
        ayStructureTaskSon.setUpdatedId(CurrentUser.getCurrentUserId());
        ayStructureTaskSon.setUpdatedBy(CurrentUser.getCurrentUserFullName());
        return this.update(ayStructureTaskSon, wrapper);
    }

    @Override
    public void sendInsertTaskMsg(AyStructureTaskSon ayStructureTaskSon) {
        TaskRequestDto taskRequestDto=new TaskRequestDto();
        taskRequestDto.setTaskName(ayStructureTaskSon.getTaskName()+ayStructureTaskSon.getId().toString());
        taskRequestDto.setId(ayStructureTaskSon.getId());
        taskRequestDto.setDeviceId(ayStructureTaskSon.getCameraId());
        taskRequestDto.setDeviceName(ayStructureTaskSon.getCameraName());
        taskRequestDto.setRtspUrl(ayStructureTaskSon.getVideoUrl());
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("OpType","insertTask");
        jsonObject.put("Data", taskRequestDto);
        MqttOp.publish(MediaMqConstants.STRUCTURE_TASK_TOPIC, JSON.toJSONString(jsonObject));
    }

    @Override
    public void sendDeleteTaskMsg(String taskId) {
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("OpType","deleteTask");
        jsonObject.put("Data", taskId);
        MqttOp.publish(MediaMqConstants.STRUCTURE_TASK_TOPIC, JSON.toJSONString(jsonObject));
    }
    /**
     * 结构化任务添加前置验证
     *
     * @param ayStructureTaskDto
     * @return false验证未通过 true验证通过
     */
    public Boolean addFrontVerify(AyStructureTaskSonDto ayStructureTaskDto) {

        List<AyCameraVo> ayCameraVos = ayStructureTaskDto.getAyCameraVos();
        //查询设备是否有未删除的分析任务
        List<String> cameraIds=ayCameraVos.stream().map(AyCameraVo::getCameraId).collect(Collectors.toList());

        List<AyStructureTaskSon> taskSons = this.list(new LambdaQueryWrapper<AyStructureTaskSon>()
                .in(AyStructureTaskSon::getCameraId, cameraIds)
                .eq(AyStructureTaskSon::getIsDeleted, DeleteStatusEnum.NOT_DELETED.getValue()));
        if(taskSons.isEmpty()){
            return true;
        }
        Iterator<AyCameraVo> cameraVoIterator = ayCameraVos.iterator();
        while (cameraVoIterator.hasNext()) {
            AyCameraVo cameraVo = cameraVoIterator.next();
            //过滤已经存在的camera
            AyStructureTaskSon taskSon=taskSons.stream().filter(d->d.getCameraId().equals(cameraVo.getCameraId())).findAny().orElse(null);
            if (!Objects.isNull(taskSon)) {
                cameraVoIterator.remove();
            }
        }
        return !ayCameraVos.isEmpty();
    }
    @Override
    public void buildDeleteAndStartTaskSon(List<AyStructureTaskSon> taskSonList,List<AyStructureTaskSon> deleteTaskSons,List<AyStructureTaskSon> insertTaskSons)
    {
        List<AyStructureTaskSon> deleteHandleTaskSons = taskSonList.stream().filter(item -> item.getStatus() == TaskStatusEnum.FINISHED.getValue()).collect(Collectors.toList());
        if(!deleteHandleTaskSons.isEmpty()){
            deleteHandleTaskSons.forEach(a -> deleteTaskSons.add(buildDeleteTaskSon(a)));
            deleteHandleTaskSons.forEach(a -> insertTaskSons.add(buildInsertTaskSon(a)));
        }
    }
    @Override
    public void buildStartTaskSon(List<AyStructureTaskSon> taskSonList,List<AyStructureTaskSon> startTaskSons)
    {
        List<AyStructureTaskSon> startHandleTaskSons = taskSonList.stream().filter(item -> item.getStatus() == TaskStatusEnum.NOT_STARTED.getValue()||item.getStatus()==TaskStatusEnum.UNUSUAL.getValue()).collect(Collectors.toList());
        startHandleTaskSons.forEach(a -> startTaskSons.add(buildStartTaskSon(a)));
    }

    @Override
    public void buildStopTaskSon(List<AyStructureTaskSon> taskSonList, List<AyStructureTaskSon> stopTaskSons) {
        taskSonList.forEach(a -> stopTaskSons.add(buildStopTaskSon(a)));
    }

    @Override
    public AyStructureTaskSon getByTaskId(String taskId) {
        LambdaQueryWrapper<AyStructureTaskSon> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AyStructureTaskSon::getTaskId, taskId);
        return this.getOne(wrapper);
    }

    @Override
    public List<String> getTaskIds(Integer structureTaskId) {
        LambdaQueryWrapper<AyStructureTaskSon> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AyStructureTaskSon::getStructureTaskId, structureTaskId);
        wrapper.isNotNull(AyStructureTaskSon::getTaskId);
        wrapper.select(AyStructureTaskSon::getTaskId);
        List<Object> infos = this.listObjs(wrapper);
        String[] taskIds =infos.toArray(new String[]{});
        return Arrays.asList(taskIds);
    }
    @Override
    public List<String> getTaskIds(Integer structureTaskId,String deviceIds) {
        LambdaQueryWrapper<AyStructureTaskSon> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AyStructureTaskSon::getStructureTaskId, structureTaskId);
        wrapper.in(AyStructureTaskSon::getCameraId,Arrays.asList(deviceIds.split(",")));
        wrapper.isNotNull(AyStructureTaskSon::getTaskId);
        wrapper.select(AyStructureTaskSon::getTaskId);
        List<Object> infos = this.listObjs(wrapper);
        String[] taskIds =infos.toArray(new String[]{});
        return Arrays.asList(taskIds);
    }
    @Override
    public String[] getRunTaskDeviceIds(String[] deviceIds){
        LambdaQueryWrapper<AyStructureTaskSon> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AyStructureTaskSon::getStatus, TaskStatusEnum.RUNING.getValue());
        wrapper.eq(AyStructureTaskSon::getIsDeleted, DeleteStatusEnum.NOT_DELETED.getValue());
        wrapper.in(AyStructureTaskSon::getCameraId,Arrays.asList(deviceIds));
        wrapper.select(AyStructureTaskSon::getCameraId);
        List<Object> infos = this.listObjs(wrapper);
        String[] cameraIds =infos.toArray(new String[]{});
        return cameraIds;
    }
    @Override
    public List<AyStructureTaskSon> selectUnusualTaskSons(List<Integer> ids){
        LambdaQueryWrapper<AyStructureTaskSon> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AyStructureTaskSon::getStatus, TaskStatusEnum.UNUSUAL.getValue());
        wrapper.in(AyStructureTaskSon::getId,ids);
        return this.list(wrapper);
    }
    private AyStructureTaskSon buildDeleteTaskSon(AyStructureTaskSon taskSon) {
        AyStructureTaskSon deleteTaskSon = new AyStructureTaskSon();
        deleteTaskSon.setId(taskSon.getId());
        deleteTaskSon.setIsDeleted(DeleteStatusEnum.DELETED.getValue());
        return deleteTaskSon;
    }

    private AyStructureTaskSon buildStartTaskSon(AyStructureTaskSon taskSon) {
        AyStructureTaskSon startTaskSon = new AyStructureTaskSon();
        startTaskSon.setId(taskSon.getId());
        startTaskSon.setTaskName(taskSon.getTaskName());
        startTaskSon.setCameraId(taskSon.getCameraId());
        startTaskSon.setCameraName(taskSon.getCameraName());
        startTaskSon.setVideoUrl(taskSon.getVideoUrl());
        startTaskSon.setStatus(TaskStatusEnum.CREATED.getValue());
        startTaskSon.setBeginTime(LocalDateTime.now());
        startTaskSon.setEndTime(null);
        return startTaskSon;
    }
    private AyStructureTaskSon buildStopTaskSon(AyStructureTaskSon taskSon) {
        AyStructureTaskSon stopTaskSon = new AyStructureTaskSon();
        stopTaskSon.setId(taskSon.getId());
        stopTaskSon.setStatus(TaskStatusEnum.FINISHED.getValue());
        stopTaskSon.setTaskId(taskSon.getTaskId());
        stopTaskSon.setEndTime(LocalDateTime.now());
        return stopTaskSon;
    }

    private AyStructureTaskSon buildInsertTaskSon(AyStructureTaskSon taskSon) {
        AyStructureTaskSon insertTaskSon = new AyStructureTaskSon();

        insertTaskSon.setStructureTaskId(taskSon.getStructureTaskId());
        insertTaskSon.setTaskName(taskSon.getTaskName());
        insertTaskSon.setCameraId(taskSon.getCameraId());
        insertTaskSon.setCameraName(taskSon.getCameraName());
        insertTaskSon.setVideoUrl(taskSon.getVideoUrl());
        insertTaskSon.setStatus(TaskStatusEnum.CREATED.getValue());
        insertTaskSon.setType(taskSon.getType());
        insertTaskSon.setBeginTime(LocalDateTime.now());
        insertTaskSon.setEndTime(null);

        return insertTaskSon;
    }
}
